aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/groups/[groupId]/expenses
diff options
context:
space:
mode:
authorAnkit Bahl <ankit2bahl@gmail.com>2024-01-19 13:38:18 -0800
committerGitHub <noreply@github.com>2024-01-19 16:38:18 -0500
commitae7cb2ccc84cf25332d1efabeb197a5e1b05d029 (patch)
treeba9df97e54789962dda8fcdc10d06b23696c9558 /src/app/groups/[groupId]/expenses
parent3735509fea74afddb3d5bc0eab57c3f03a239354 (diff)
Added search bar for expense list page (#52)
* Added search bar for expense list page * Change search input styling --------- Co-authored-by: Sebastien Castiel <sebastien@castiel.me>
Diffstat (limited to 'src/app/groups/[groupId]/expenses')
-rw-r--r--src/app/groups/[groupId]/expenses/expense-list.tsx164
1 files changed, 91 insertions, 73 deletions
diff --git a/src/app/groups/[groupId]/expenses/expense-list.tsx b/src/app/groups/[groupId]/expenses/expense-list.tsx
index 73c8c6e..b083ab6 100644
--- a/src/app/groups/[groupId]/expenses/expense-list.tsx
+++ b/src/app/groups/[groupId]/expenses/expense-list.tsx
@@ -1,6 +1,7 @@
'use client'
import { CategoryIcon } from '@/app/groups/[groupId]/expenses/category-icon'
import { Button } from '@/components/ui/button'
+import { SearchBar } from '@/components/ui/search-bar'
import { getGroupExpenses } from '@/lib/api'
import { cn } from '@/lib/utils'
import { Expense, Participant } from '@prisma/client'
@@ -8,7 +9,7 @@ import dayjs, { type Dayjs } from 'dayjs'
import { ChevronRight } from 'lucide-react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
-import { Fragment, useEffect } from 'react'
+import { Fragment, useEffect, useState } from 'react'
type Props = {
expenses: Awaited<ReturnType<typeof getGroupExpenses>>
@@ -63,6 +64,7 @@ export function ExpenseList({
participants,
groupId,
}: Props) {
+ const [searchText, setSearchText] = useState('')
useEffect(() => {
const activeUser = localStorage.getItem('newGroup-activeUser')
const newUser = localStorage.getItem(`${groupId}-newUser`)
@@ -86,86 +88,102 @@ export function ExpenseList({
const router = useRouter()
const groupedExpensesByDate = getGroupedExpensesByDate(expenses)
-
return expenses.length > 0 ? (
- Object.values(EXPENSE_GROUPS).map((expenseGroup: string) => {
- const groupExpenses = groupedExpensesByDate[expenseGroup]
- if (!groupExpenses) return null
- return (
- <div key={expenseGroup}>
- <div
- className={
- 'text-muted-foreground text-xs pl-4 sm:pl-6 py-1 font-semibold sticky top-16 bg-white dark:bg-[#1b1917]'
- }
- >
- {expenseGroup}
- </div>
- {groupExpenses.map((expense: any) => (
+ <>
+ <SearchBar onChange={(e) => setSearchText(e.target.value)} />
+ {Object.values(EXPENSE_GROUPS).map((expenseGroup: string) => {
+ const groupExpenses = groupedExpensesByDate[expenseGroup]
+ if (!groupExpenses) return null
+ return (
+ <div key={expenseGroup}>
<div
- key={expense.id}
- className={cn(
- 'flex justify-between sm:mx-6 px-4 sm:rounded-lg sm:pr-2 sm:pl-4 py-4 text-sm cursor-pointer hover:bg-accent gap-1 items-stretch',
- expense.isReimbursement && 'italic',
- )}
- onClick={() => {
- router.push(`/groups/${groupId}/expenses/${expense.id}/edit`)
- }}
+ className={
+ 'text-muted-foreground text-xs pl-4 sm:pl-6 py-1 font-semibold sticky top-16 bg-white dark:bg-[#1b1917]'
+ }
>
- <CategoryIcon
- category={expense.category}
- className="w-4 h-4 mr-2 mt-0.5 text-muted-foreground"
- />
- <div className="flex-1">
- <div
- className={cn('mb-1', expense.isReimbursement && 'italic')}
- >
- {expense.title}
- </div>
- <div className="text-xs text-muted-foreground">
- Paid by{' '}
- <strong>{getParticipant(expense.paidById)?.name}</strong> for{' '}
- {expense.paidFor.map((paidFor: any, index: number) => (
- <Fragment key={index}>
- {index !== 0 && <>, </>}
- <strong>
- {
- participants.find(
- (p) => p.id === paidFor.participantId,
- )?.name
- }
- </strong>
- </Fragment>
- ))}
- </div>
- </div>
- <div className="flex flex-col justify-between items-end">
+ {expenseGroup}
+ </div>
+ {groupExpenses
+ .filter(
+ (exp) =>
+ exp.title.toLowerCase().match(searchText.toLowerCase()) !==
+ null,
+ )
+ .map((expense: any) => (
<div
+ key={expense.id}
className={cn(
- 'tabular-nums whitespace-nowrap',
- expense.isReimbursement ? 'italic' : 'font-bold',
+ 'flex justify-between sm:mx-6 px-4 sm:rounded-lg sm:pr-2 sm:pl-4 py-4 text-sm cursor-pointer hover:bg-accent gap-1 items-stretch',
+ expense.isReimbursement && 'italic',
)}
+ onClick={() => {
+ router.push(
+ `/groups/${groupId}/expenses/${expense.id}/edit`,
+ )
+ }}
>
- {currency} {(expense.amount / 100).toFixed(2)}
- </div>
- <div className="text-xs text-muted-foreground">
- {formatDate(expense.expenseDate)}
+ <CategoryIcon
+ category={expense.category}
+ className="w-4 h-4 mr-2 mt-0.5 text-muted-foreground"
+ />
+ <div className="flex-1">
+ <div
+ className={cn(
+ 'mb-1',
+ expense.isReimbursement && 'italic',
+ )}
+ >
+ {expense.title}
+ </div>
+ <div className="text-xs text-muted-foreground">
+ Paid by{' '}
+ <strong>{getParticipant(expense.paidById)?.name}</strong>{' '}
+ for{' '}
+ {expense.paidFor.map((paidFor: any, index: number) => (
+ <Fragment key={index}>
+ {index !== 0 && <>, </>}
+ <strong>
+ {
+ participants.find(
+ (p) => p.id === paidFor.participantId,
+ )?.name
+ }
+ </strong>
+ </Fragment>
+ ))}
+ </div>
+ </div>
+ <div className="flex flex-col justify-between items-end">
+ <div
+ className={cn(
+ 'tabular-nums whitespace-nowrap',
+ expense.isReimbursement ? 'italic' : 'font-bold',
+ )}
+ >
+ {currency} {(expense.amount / 100).toFixed(2)}
+ </div>
+ <div className="text-xs text-muted-foreground">
+ {formatDate(expense.expenseDate)}
+ </div>
+ </div>
+ <Button
+ size="icon"
+ variant="link"
+ className="self-center hidden sm:flex"
+ asChild
+ >
+ <Link
+ href={`/groups/${groupId}/expenses/${expense.id}/edit`}
+ >
+ <ChevronRight className="w-4 h-4" />
+ </Link>
+ </Button>
</div>
- </div>
- <Button
- size="icon"
- variant="link"
- className="self-center hidden sm:flex"
- asChild
- >
- <Link href={`/groups/${groupId}/expenses/${expense.id}/edit`}>
- <ChevronRight className="w-4 h-4" />
- </Link>
- </Button>
- </div>
- ))}
- </div>
- )
- })
+ ))}
+ </div>
+ )
+ })}
+ </>
) : (
<p className="px-6 text-sm py-6">
Your group doesn’t contain any expense yet.{' '}